package com.tomicalab.mobiletoken.ckca;

import iaik.pkcs.pkcs11.wrapper.CK_TOKEN_INFO;
import iaik.pkcs.pkcs11.wrapper.PKCS11Exception;

import java.io.UnsupportedEncodingException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.security.spec.InvalidKeySpecException;
import java.util.Arrays;
import java.util.Random;

import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.DESKeySpec;
import com.tomicalab.mobiletoken.ckca.utils.Constant;
import com.tomicalab.mobiletoken.ckca.utils.CustomProgressDialog;
import com.tomicalab.mobiletoken.ckca.utils.P11Other;
import com.tomicalab.mobiletoken.ckca.utils.StorePreferences;

import android.app.Activity;
import android.app.AlertDialog.Builder;
import android.content.Context;
import android.content.DialogInterface;
import android.content.res.Resources;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.util.Base64;
import android.util.Log;
import android.view.View;
import android.widget.EditText;
import android.widget.ImageButton;
import android.widget.Toast;

public class UnBlockPIN extends Activity{
	private EditText etSerial;
	private EditText etRN;
	private EditText etUC;
	
	private ImageButton iBGenRN;
	private ImageButton iBUnBlock;
	
	private Context context;
	private Resources res;
	
	private StorePreferences storeRN;
	private boolean doInOnCreate = true;
	
	private static byte[] CRC32OK = {(byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00};
	
	private static CustomProgressDialog progressDialog;
	private static handler handler;
	
	public class handler extends Handler {
		String sopin, newpin;
		public void sleep(long delayMillis, int msgID, Object obj) {
            this.removeMessages(msgID);
            Message msg = new Message();
            msg.what = msgID;
            msg.obj  = obj;
            sendMessageDelayed(msg, delayMillis);
        }
		public void sleep(long delayMillis, int msgID, Object obj, String sopin, String newpin) {
            this.removeMessages(msgID);
            Message msg = new Message();
            msg.what = msgID;
            msg.obj  = obj;
            this.sopin = sopin;
            this.newpin = newpin;
            sendMessageDelayed(msg, delayMillis);
        }
		
		public void handleMessage(Message msg) {
			switch(msg.what) {
			case Constant.SHOWPROGRESSDIALOG:
				Log.e(Constant.Debug, "SHOWPROGRESSDIALOG");
				progressDialog.show();
				super.handleMessage(msg);
				break;
			case Constant.CLOSEPROGRESSDIALOG:
				progressDialog.dismiss();
				super.handleMessage(msg);
				break;
			case Constant.SHOWERRINFO:
				if (null != msg.obj)
				{
					if(msg.obj.toString().compareTo(res.getString(R.string.inform_handset_connectfail))==0)
					{
						String title, button;
			    		button = res.getString(R.string.inform_button_OK);
						title = res.getString(R.string.inform_title);
						new Builder(context)
				    	.setTitle(title)
				    	.setMessage(msg.obj.toString())
				    	.setPositiveButton(button, new DialogInterface.OnClickListener() {
							
							@Override
							public void onClick(DialogInterface arg0, int arg1) {
								finish();
							}
						}).show();
					}
					else
						Constant.showMessage(msg.obj.toString(), context, res);
				}
				super.handleMessage(msg);
				break;
			case Constant.UNBLOCKPIN:
				doUnblockPIN(sopin, newpin);
				super.handleMessage(msg);
				break;
			}
			
		}
	}
	
	
	@Override
	protected void onCreate(Bundle savedInstanceState) {
		// TODO Auto-generated method stub
		Log.i(Constant.Debug, "onCreate UnBlockPIN");
		doInOnCreate = false;
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_unblockpin);
		context = this;
		res = this.getResources();
		
		etRN = (EditText) findViewById(R.id.et_unblockpin_rn);

		etSerial = (EditText) findViewById(R.id.et_unblockpin_serial);
		etSerial.setKeyListener(null);
		etUC = (EditText) findViewById(R.id.et_unblockpin_uc);
		
		iBGenRN = (ImageButton) findViewById(R.id.btn_unblockpin_genRN);
		iBUnBlock = (ImageButton) findViewById(R.id.btn_unblockpin_unblock);
		
		storeRN = new StorePreferences(context);
		
		progressDialog = new CustomProgressDialog(context);
		progressDialog.setCancelable(false);
		handler = new handler();
		
		iBGenRN.setOnClickListener(new View.OnClickListener() {
			
			@Override
			public void onClick(View arg0) {
				if(P11Other.isTokenPlugned == 0)
				{
					Constant.showMessage(res.getString(R.string.inform_handset_plugout), context, res);
				}
				else
				{
					if(P11Other.isLoadlib == 1)
					{
						String series = etSerial.getText().toString().trim();
						String RN = genRN(series);
						etRN.setText(RN);
						Constant.showMessage(res.getString(R.string.inform_unblock_notice), context, res);
						storeRN.setRN(RN);
					}
					else
					{
						Constant.showMessage(res.getString(R.string.inform_handset_loadLib), context, res);
					}
				}
			}
		});
		
		iBUnBlock.setOnClickListener(new View.OnClickListener() {
			
			@Override
			public void onClick(View v) {
				Constant.hideSoftKeyboard(UnBlockPIN.this, v);
				if(P11Other.isTokenPlugned == 0)
				{
					Constant.showMessage(res.getString(R.string.inform_handset_plugout), context, res);
				}
				else
				{
					if(P11Other.isLoadlib == 0)
					{
						Constant.showMessage(res.getString(R.string.inform_handset_loadLib), context, res);
					}
					else
					{
						String rn = storeRN.getRN().trim();
						String uc = etUC.getText().toString().trim();
						try {
							if(uc.length() != 0)
							{
								String SO = getSO(uc, rn.substring(3));
								Log.i(Constant.Debug, "SO returned: "+SO);
								if(SO.compareTo("2") == 0 || SO.compareTo("0") == 0)
								{
									Constant.showMessage(res.getString(R.string.inform_unblock_dataerror), context, res);
								} else if(SO.compareTo("1")==0)
								{
									Constant.showMessage(res.getString(R.string.inform_unblock_wrongRN), context, res);
								}
								else
								{
									String decodedSO = decodeSOPIN(SO);
									Log.i(Constant.Debug, "SO decoded: "+decodedSO);
									progressDialog.setShowInfo(res.getString(R.string.inform_unblock_dounblock));
									handler.sleep(0, Constant.SHOWPROGRESSDIALOG, "");
									handler.sleep(100, Constant.UNBLOCKPIN, "", decodedSO, "12345678");
								}
							}
							else
							{
								Constant.showMessage(res.getString(R.string.inform_unblock_noUC), context, res);
							}
						} catch(Exception e)
						{
							Constant.showMessage(res.getString(R.string.inform_unblock_dataerror), context, res);
						}						
					}
				}
			}
		});
		
		if(P11Other.isTokenPlugned == 0)
		{
			Constant.showMessage(res.getString(R.string.inform_handset_plugout), context, res);
			etSerial.setText("");
			etRN.setText("");
			etUC.setText("");
		}
		else
		{
			if(P11Other.isLoadlib == 0)
			{
				Constant.showMessage(res.getString(R.string.inform_unblock_notInit), context, res);
				etSerial.setText("");
				etRN.setText("");
				etUC.setText("");
			}
			else
			{
				CK_TOKEN_INFO tokenInfo = P11Other.getTokenInformation();
				String series = new String(tokenInfo.serialNumber);
				etSerial.setText(series);
			}
		}
	}
	
	@Override
	protected void onResume() {
		super.onResume();
		Log.i(Constant.Debug, "onResume UnBlockPIN");
		if(doInOnCreate == false)
		{
			doInOnCreate = true;
		}
		else
		{
			if(P11Other.isTokenPlugned == 0)
			{
				Constant.showMessage(res.getString(R.string.inform_handset_plugout), context, res);
				etSerial.setText("");
				etRN.setText("");
				etUC.setText("");
			}
			else
			{
				if(P11Other.isLoadlib == 0)
				{
					Constant.showMessage(res.getString(R.string.inform_unblock_notInit), context, res);
					etSerial.setText("");
					etRN.setText("");
					etUC.setText("");
				}
				else
				{
					CK_TOKEN_INFO tokenInfo = P11Other.getTokenInformation();
					String series = new String(tokenInfo.serialNumber);
					etSerial.setText(series);
				}
			}
		}
	}

	private void doUnblockPIN(final String sopin, final String newpin)
	{
		new Thread() {
			public void run() {
				try {
					int rv = P11Other.unblockPIN(sopin, newpin);
					handler.sleep(0, Constant.CLOSEPROGRESSDIALOG, "");
					
					if(rv == 0) {
						handler.sleep(10, Constant.SHOWERRINFO, res.getString(R.string.inform_unblock_unblockOK));
					} else if(rv == 1)
					{
						handler.sleep(10, Constant.SHOWERRINFO, res.getString(R.string.inform_unblock_wrongSOpin));
					} else {
						handler.sleep(10, Constant.SHOWERRINFO, res.getString(R.string.inform_unblock_generalerror));
					}
					
				} catch (PKCS11Exception e) {
					e.printStackTrace();
				}
			}
		}.start();
	}
	
	public static String genRN(String SN)
	{
		if(SN.compareTo("")==0)
			return null;
		String RN = "";
		
		String tmp1 = SN.concat("#").concat(radom10ByteNumber());
		
		byte[] tmpByte=null;
		try {
			tmpByte = tmp1.getBytes("UTF-8");
		} catch (UnsupportedEncodingException e1) {
			e1.printStackTrace();
		}
		byte[] tmpByteCRC32 = ComputeCRC(tmpByte);
		
		byte[] rv = new byte[tmpByte.length + tmpByteCRC32.length];
		System.arraycopy(tmpByte, 0, rv, 0, tmpByte.length);
		System.arraycopy(tmpByteCRC32, 0, rv, tmpByte.length, tmpByteCRC32.length);
		
		int x = (tmp1.length()+4) % 8;
		int length = tmp1.length()+4+8-x;
		int numBlock = length/8;
		
		byte[] dataRN = new byte[length];
		Arrays.fill(dataRN, (byte)(length - tmpByte.length - tmpByteCRC32.length));
		System.arraycopy(rv, 0, dataRN, 0, rv.length);
		
		byte[] block[] = new byte[length/8][8];
		
		for(int i=0; i<numBlock; i++)
		{
			System.arraycopy(dataRN, i*8, block[i], 0, 8);
		}
		
		byte[] bt[] = new byte[length/8][8];
		
		for(int i=0; i<numBlock; i++)
		{
			try {
				bt[i] = encryptBlock(block[i]);
			} catch (InvalidKeyException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			} catch (InvalidKeySpecException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			} catch (NoSuchAlgorithmException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			} catch (NoSuchPaddingException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			} catch (IllegalBlockSizeException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			} catch (BadPaddingException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			} catch (UnsupportedEncodingException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}

		
		byte[] encTDES = new byte[length];
		
		for(int i=0; i<numBlock; i++)
		{
			System.arraycopy(bt[i], 0, encTDES, i*8, 8);
		}
		
	    byte[] datatosend = new byte[length+6];
	    Arrays.fill(datatosend, (byte)0);
	    
	    byte[] prefix=null;
		try {
			prefix = "ostt1_".getBytes("UTF-8");
		} catch (UnsupportedEncodingException e) {
			e.printStackTrace();
		}
	    
	    System.arraycopy(prefix, 0, datatosend, 0, prefix.length);
	    System.arraycopy(encTDES, 0, datatosend, prefix.length, encTDES.length);
	    
	    RN = Base64.encodeToString(datatosend, Base64.DEFAULT);
	    String _prefix = "TT_";
		
		return _prefix+RN;
	}
	
	public static String getSN(String RN)
	{
		if(RN.compareTo("")==0)
			return null;
		
		String SN = "";
		
		byte[] tmp = Base64.decode(RN, Base64.DEFAULT);
		
		byte[] rawRN = new byte[tmp.length]; 
		System.arraycopy(tmp, 0, rawRN, 0, tmp.length);
		
		if((tmp.length-6) % 8 != 0)
			return null;
		
		int numBlock = (tmp.length-6)/8;
		int length = (tmp.length-6);
		
		byte[] block[] = new byte[numBlock][8];
		byte[] bt[] = new byte[numBlock][8];
		int n = 6;
		for(int i=0; i<numBlock; i++)
		{
			System.arraycopy(rawRN, n, block[i], 0, 8);
			n += 8;
		}

    	for(int i=0; i<numBlock; i++)
    	{
    		try {
				bt[i] = decryptBlock(block[i]);
			} catch (InvalidKeyException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			} catch (InvalidKeySpecException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			} catch (NoSuchAlgorithmException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			} catch (NoSuchPaddingException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			} catch (IllegalBlockSizeException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			} catch (BadPaddingException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			} catch (UnsupportedEncodingException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
    	}


	    byte[] decRawRN = new byte[length];
	    
	    for(int i=0; i<numBlock; i++)
	    {
	    	System.arraycopy(bt[i], 0, decRawRN, i*8, 8);
	    }
	    
	    int last_byte = decRawRN[length-1];
	    
	    byte[] temp = new byte[length-last_byte];
	    
	    System.arraycopy(decRawRN, 0, temp, 0, length-last_byte);
	    
	    byte[] B = ComputeCRC(temp);
		
	    if(!Arrays.equals(B, CRC32OK))
	    {
	    	System.out.println("Checksum RN fail!");
	    	return null;
	    }
		
		String temp1[] = null;
		try {
			temp1 = new String(decRawRN, "UTF-8").split("#");
		} catch (UnsupportedEncodingException e) {
			e.printStackTrace();
		}
		
		SN = temp1[0];
		
		return SN;
	}
	
	public static String genUC(String PIN, String RN)
	{
		if(PIN.compareTo("")==0 || RN.compareTo("")==0)
			return null;
		
		String UC = "";
		
		String tmp = PIN.concat("#").concat(RN);
		System.out.println("debug: "+tmp);
		byte[] RawTmp=null;
		try {
			RawTmp = tmp.getBytes("UTF-8");
		} catch (UnsupportedEncodingException e1) {
			e1.printStackTrace();
		}
		byte[] CRC32A = ComputeCRC(RawTmp);
		
		byte[] rv = new byte[RawTmp.length+CRC32A.length];
		System.arraycopy(RawTmp, 0, rv, 0, RawTmp.length);
		System.arraycopy(CRC32A, 0, rv, RawTmp.length, CRC32A.length);
		
		int x = (tmp.length()+4) % 8;
		int length = tmp.length()+4+8-x;
		int numBlock = length/8;
		
		byte[] dataUC = new byte[length];
		Arrays.fill(dataUC, (byte)(length - RawTmp.length - CRC32A.length));
		System.arraycopy(rv, 0, dataUC, 0, rv.length);
		
		byte[] block[] = new byte[length/8][8];
		
		for(int i=0; i<numBlock; i++)
		{
			System.arraycopy(dataUC, i*8, block[i], 0, 8);
		}
		byte[] bt[] = new byte[length/8][8];
		
		for(int i=0; i<numBlock; i++)
		{
			try {
				bt[i] = encryptBlock(block[i]);
			} catch (InvalidKeyException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			} catch (InvalidKeySpecException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			} catch (NoSuchAlgorithmException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			} catch (NoSuchPaddingException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			} catch (IllegalBlockSizeException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			} catch (BadPaddingException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			} catch (UnsupportedEncodingException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
		
		byte[] encTDES = new byte[length];
		
		for(int i=0; i<numBlock; i++)
		{
			System.arraycopy(bt[i], 0, encTDES, i*8, 8);
		}
		
		UC = Base64.encodeToString(encTDES, Base64.DEFAULT);
		return UC;
	}
	
	public static String getSO(String UC, String mRN)
	{
		if(UC.compareTo("") == 0)
			return null;
		
		String SO = "";
		
		byte[] tmp = Base64.decode(UC, Base64.DEFAULT);
		
		byte[] RawSO = new byte[tmp.length];
		System.arraycopy(tmp, 0, RawSO, 0, tmp.length);
		
		if((tmp.length % 8) != 0)
			return "2";
		
		int length = tmp.length;
		int numBlock = length/8;
		
		byte[] block[] = new byte[numBlock][8];
		byte[] bt[] = new byte[numBlock][8];
		
		for(int i=0; i<numBlock; i++)
		{
			System.arraycopy(RawSO, i*8, block[i], 0, 8);
		}
		
    	for(int i=0; i<numBlock; i++)
    	{
    		try {
				bt[i] = decryptBlock(block[i]);
			} catch (InvalidKeyException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			} catch (InvalidKeySpecException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			} catch (NoSuchAlgorithmException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			} catch (NoSuchPaddingException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			} catch (IllegalBlockSizeException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			} catch (BadPaddingException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			} catch (UnsupportedEncodingException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
    	}

	    byte[] decRawUC = new byte[length];
	    Arrays.fill(decRawUC, (byte)0);
	    
	    for(int i=0; i<numBlock; i++)
	    {
	    	System.arraycopy(bt[i], 0, decRawUC, i*8, 8);
	    }
	    
	    int last_byte = decRawUC[length-1];

	    byte[] temp1 = new byte[length - last_byte];
	    System.arraycopy(decRawUC, 0, temp1, 0, length-last_byte);

	    byte[] B = ComputeCRC(temp1);
	    
	    if(!Arrays.equals(B, CRC32OK))
	    {
	    	System.out.println("Checksum UC fail!");
	    	return "0";
	    }
	    byte[] temp2 = new byte[temp1.length - 4];
	    System.arraycopy(temp1, 0, temp2, 0, temp1.length-4);

	    try {
			String temp3 = new String(temp2, "UTF-8");
			String temp4[] = temp3.split("#");
			
			if(mRN.compareTo(temp4[1]) != 0)
				return "1";
			Log.d(Constant.Debug, "RN: "+temp4[1]);
			Log.d(Constant.Debug, "SO: "+temp4[0]);
			
			return temp4[0];
		} catch (UnsupportedEncodingException e) {
			e.printStackTrace();
		}
	    return "-1";
	}
	
	public static String decodeSOPIN(String encSOPIN)
	{
		String SO = "";
		if(encSOPIN.compareTo("") == 0)
			return null;
		byte[] rawSO = Base64.decode(encSOPIN, Base64.DEFAULT);
		if((rawSO.length % 8) != 0)
			return null;
		int length = rawSO.length;
		int numBlock = length/8;
		
		byte[] block[] = new byte[numBlock][8];
		byte[] bt[] = new byte[numBlock][8];
		
		for(int i=0; i<numBlock; i++)
		{
			System.arraycopy(rawSO, i*8, block[i], 0, 8);
		}
		
    	for(int i=0; i<numBlock; i++)
    	{
    		try {
				bt[i] = decryptBlock(block[i]);
			} catch (InvalidKeyException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			} catch (InvalidKeySpecException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			} catch (NoSuchAlgorithmException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			} catch (NoSuchPaddingException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			} catch (IllegalBlockSizeException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			} catch (BadPaddingException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			} catch (UnsupportedEncodingException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
    	}
		
		byte[] decRawSO = new byte[length];
	    Arrays.fill(decRawSO, (byte)0);
	    
	    for(int i=0; i<numBlock; i++)
	    {
	    	System.arraycopy(bt[i], 0, decRawSO, i*8, 8);
	    }
	    int last_byte = decRawSO[length-1];
	    byte[] temp = new byte[length-last_byte];
	    System.arraycopy(decRawSO, 0, temp, 0, length-last_byte);
		
		try {
			SO = new String(temp, "UTF-8");
		} catch (UnsupportedEncodingException e) {
			e.printStackTrace();
		}
		return SO;
	}
	
	public static String encodeSOPIN(String SoPin)
	{
		if(SoPin.compareTo("")==0)
			return null;
		byte[] rawSo = null;
		try {
			rawSo = SoPin.getBytes("UTF-8");
		} catch (UnsupportedEncodingException e) {
			e.printStackTrace();
		}
		
		int x, length, numBlock;
		String SOPIN = "";

		x = rawSo.length % 8;
		length = rawSo.length + 8 - x;
		numBlock = length/8;
		
		byte[] dataSO = new byte[length];
		Arrays.fill(dataSO, (byte)(length - SoPin.length()));
		System.arraycopy(rawSo, 0, dataSO, 0, rawSo.length);
		
		byte[] block[] = new byte[numBlock][8];
		for(int i=0; i<numBlock; i++)
		{
			System.arraycopy(dataSO, i*8, block[i], 0, 8);
		}
		byte[] bt[] = new byte[numBlock][8];
		
		for(int i=0; i<numBlock; i++)
		{
			try {
				bt[i] = encryptBlock(block[i]);
			} catch (InvalidKeyException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			} catch (InvalidKeySpecException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			} catch (NoSuchAlgorithmException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			} catch (NoSuchPaddingException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			} catch (IllegalBlockSizeException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			} catch (BadPaddingException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			} catch (UnsupportedEncodingException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
		byte[] encSOPIN = new byte[length];
		
		for(int i=0; i<numBlock; i++)
		{
			System.arraycopy(bt[i], 0, encSOPIN, i*8, 8);
		}
		
		SOPIN = Base64.encodeToString(encSOPIN, Base64.DEFAULT);
		
		return SOPIN;
	}
	
	public static byte[] encryptBlock(byte[] block) throws InvalidKeyException, InvalidKeySpecException, NoSuchAlgorithmException, NoSuchPaddingException, IllegalBlockSizeException, BadPaddingException, UnsupportedEncodingException
	{
		if(block.length != 8)
			return null;
		
		String key1 = "12345678";
        DESKeySpec KEY1 = new DESKeySpec(key1.getBytes("UTF-8"));
        SecretKeyFactory keyFactory1 = SecretKeyFactory.getInstance("DES");
        SecretKey myDesKey1 = keyFactory1.generateSecret(KEY1);
        
        String key2 = "90abcdef";
        DESKeySpec KEY2 = new DESKeySpec(key2.getBytes("UTF-8"));
        SecretKeyFactory keyFactory2 = SecretKeyFactory.getInstance("DES");
        SecretKey myDesKey2 = keyFactory2.generateSecret(KEY2);

	    Cipher desCipher1; 
	    desCipher1 = Cipher.getInstance("DES/ECB/NoPadding");

	    desCipher1.init(Cipher.ENCRYPT_MODE, myDesKey1);
	    
	    Cipher desCipher2; 
	    desCipher2 = Cipher.getInstance("DES/ECB/NoPadding");

	    desCipher2.init(Cipher.DECRYPT_MODE, myDesKey2);
	    
	    byte[] d3 = desCipher1.doFinal(block);
	    
	    byte[] d2 = desCipher2.doFinal(d3);
	    
	    byte[] d1 = desCipher1.doFinal(d2);
	    
	    return d1;	
	}
	public static byte[] decryptBlock(byte[] block) throws InvalidKeyException, InvalidKeySpecException
	, NoSuchAlgorithmException, NoSuchPaddingException
	, IllegalBlockSizeException, BadPaddingException, UnsupportedEncodingException
	{
		if(block.length != 8)
			return null;
		
		String key1 = "12345678";
        DESKeySpec KEY1 = new DESKeySpec(key1.getBytes("UTF-8"));
        SecretKeyFactory keyFactory1 = SecretKeyFactory.getInstance("DES");
        SecretKey myDesKey1 = keyFactory1.generateSecret(KEY1);
        
        String key2 = "90abcdef";
        DESKeySpec KEY2 = new DESKeySpec(key2.getBytes("UTF-8"));
        SecretKeyFactory keyFactory2 = SecretKeyFactory.getInstance("DES");
        SecretKey myDesKey2 = keyFactory2.generateSecret(KEY2);

	    Cipher desCipher1; 
	    desCipher1 = Cipher.getInstance("DES/ECB/NoPadding");

	    desCipher1.init(Cipher.DECRYPT_MODE, myDesKey1);
	    
	    Cipher desCipher2; 
	    desCipher2 = Cipher.getInstance("DES/ECB/NoPadding");

	    desCipher2.init(Cipher.ENCRYPT_MODE, myDesKey2);
	    
	    byte[] d3 = desCipher1.doFinal(block);
	    
	    byte[] d2 = desCipher2.doFinal(d3);
	    
	    byte[] d1 = desCipher1.doFinal(d2);
	    
	    return d1;	
	}
	
	public static long UpdateCRC(byte b, long crc)
	{
		long TabVal = (crc ^ b) & 0xffL;
		for(int i=8; i>0; i--)
		{
			if((TabVal % 2) == 1)
				TabVal = (TabVal >>1) ^ 0xedb88320L;
			else
				TabVal = TabVal >> 1;
		}
		
		return (TabVal ^ ((crc>>8) & 0x00ffffffL));
	}
	
	public static byte[] ComputeCRC(byte[] bytes)
	{
		byte[] result = new byte[4];
		
		long res = 0xffffffffL;
		for(int i=0; i<bytes.length; i++)
		{
			res = UpdateCRC(bytes[i], res);
		}
		result[0] = (byte)(res & 0xffL);
		result[1] = (byte)(res >> 8);
		result[2] = (byte)(res >> 16);
		result[3] = (byte)(res >> 24);
		return result;
	}
	
	public static String radom10ByteNumber()
	{
		int START = 48;
	    int END = 57;
	    String result = "";
	    Random random = new Random();
	    for (int idx = 1; idx <= 10; ++idx){
	    	result += (char)showRandomInteger(START, END, random);
	    }
	    return result;
	}
	
	private static int showRandomInteger(int aStart, int aEnd, Random aRandom){
	    if ( aStart > aEnd ) {
	      throw new IllegalArgumentException("Start cannot exceed End.");
	    }
	    //get the range, casting to long to avoid overflow problems
	    long range = (long)aEnd - (long)aStart + 1;
	    // compute a fraction of the range, 0 <= frac < range
	    long fraction = (long)(range * aRandom.nextDouble());
	    int randomNumber =  (int)(fraction + aStart);    
	    return randomNumber;
	  }

}
